package com.ruoyi.resume.service.impl;

import com.ruoyi.resume.domain.model.Candidate;
import com.ruoyi.resume.domain.model.Job;
import com.ruoyi.resume.domain.model.ResumeTag;
import com.ruoyi.resume.domain.model.Tag;
import com.ruoyi.resume.domain.model.match.JobLabels;
import com.ruoyi.resume.domain.model.match.JobMatchVo;
import com.ruoyi.resume.domain.model.match.ResumeMatch;
import com.ruoyi.resume.domain.model.match.TagWeight;
import com.ruoyi.resume.enums.MatchPrompt;
import com.ruoyi.resume.mapper.JobMapper;
import com.ruoyi.resume.mapper.ResumeTagMapper;
import com.ruoyi.resume.mapper.TagMapper;
import com.ruoyi.resume.service.MatchResumeService;
import com.ruoyi.resume.utils.deepseek.DeepSeekV3Client;
import com.ruoyi.resume.utils.minIO.MinIOUtil;
import io.minio.BucketExistsArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.errors.*;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j
@Service
public class MatchResumeServiceImpl implements MatchResumeService {

    @Autowired
    private  TagMapper tagMapper;

    @Autowired
    private ResumeTagMapper resumeTagMapper;

    @Autowired
    private JobMapper jobMapper;

    @Autowired
    private MinioClient minioClient;

    private Map<String,Integer> education = new HashMap<>();

    //构造函数
    public MatchResumeServiceImpl(){
        education.put("学历不限",-1);
        education.put("高中",0);
        education.put("大专",1);
        education.put("本科",2);
        education.put("硕士",3);
        education.put("博士",4);
    }

    /**
     * 人岗匹配[主逻辑]
     * */
    @Override
    public List<ResumeMatch> matchResume(JobMatchVo jobDescription) {
        //1.提取岗位标签 大模型+标签体系
        JobLabels jobLabels = getJobLabels(jobDescription);

        //2.计算匹配度并排序
        return scoreAndSortResume(jobLabels);
    }

    /**
     * 更新岗位的候选人[主逻辑]
     * 注意：与上方不同点主要在于不走AI
     * */
    @Override
    public List<ResumeMatch> updateCandidateId(Integer jobId) {
        //先从数据库中提取该岗位的岗位标签
        Job job = jobMapper.findJobById(jobId);
        JobLabels jobLabels = convertToJobLabels(job);
        log.info("岗位id为" + jobId+" 查询岗位标签为: "+jobLabels);
        return scoreAndSortResume(jobLabels);
    }

    /**
     * 匹配效果可视化
     * */
    @Override
    public String matchResumeVisual(int jobId) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        //1.获取岗位描述及标签信息
        Job job = jobMapper.findJobById(jobId);
        //2.获取匹配的简历id,得分,简历标签
        List<Candidate>  candidateList = jobMapper.findCandidateIdsByJobId(jobId);
        //查询每个候选人的标签
        StringBuilder candidateInfos = new StringBuilder();
        candidateList.forEach(candidate -> {
            List<ResumeTag> tags = resumeTagMapper.selectResumeTagsByResumeId(candidate.getResumeId());
            candidate.setTags(tags);
            candidateInfos.append(candidate.toString()).append("\n");
        });
        //3.调用AI生成HTML

        return String.format(MatchPrompt.VISUAL_PROMPT.getPrompt(),
                job.getTitle(),
                job.getDescription(),
                job.getTags(),
                job.getFilters(),
                candidateInfos.toString());
    }


    /**
     * 提取岗位标签
     * */
    public  JobLabels getJobLabels(JobMatchVo jobDescription){
        //1.先从数据库中获取标签体系
        List<Tag> labels = tagMapper.selectAllTags();
        String prompt = getMessage(jobDescription, labels);
        log.info("提示词为: "+prompt);

        //3.调用大模型
        //String output = Glm.chatGLM4(prompt);
        String output = DeepSeekV3Client.ds(prompt);
        log.info("原始输出为: "+output);

        //4.处理返回结果:提取标签,并进行硬性条件的提取
        String[] labelArray = processRet(output);//可能为null，待做异常处理蛤
        JobLabels jobLabels = new JobLabels(new ArrayList<>(),new ArrayList<>());
        StringBuilder sb = new StringBuilder();
        StringBuilder sb2 = new StringBuilder();
        if(labelArray!=null){
            for(String tmp : labelArray){
                if(tmp.charAt(0) == '#'){
                    jobLabels.getFilters().add(tmp.substring(1));
                    sb.append(tmp.substring(1)).append(",");
                }else{
                    sb2.append(tmp).append(",");
                    String[] t = tmp.split(":");
                    jobLabels.getConditions().add(new TagWeight(t[0],Double.parseDouble(t[1])));
                    //TODO:在此处记录标签在JD中是否出现：以作为逆文档频率的依据[tag表可增加count字段]
                }
            }
            sb.deleteCharAt(sb.length()-1);
            sb2.deleteCharAt(sb2.length()-1);
            //保存岗位标签及权重至数据库中
            jobMapper.updateJobLabels(jobDescription.getJobId(),sb.toString(),sb2.toString());
            log.info("岗位标签已关联到岗位表中,岗位ID为:{},硬性条件为{},软性条件为{} ",jobDescription.getJobId(),sb.toString(),sb2.toString());
        }

        return jobLabels;
    }


    /**
     * 对简历进行评分排序
     * */
    private List<ResumeMatch> scoreAndSortResume(JobLabels jobLabels) {
        //岗位所包含的硬性标签
        List<String> hardConditions = jobLabels.getFilters();
        //岗位包含的其他标签
        List<TagWeight> conditions = jobLabels.getConditions();

        int[] hard = getEducationAndExperience(hardConditions);
        //查询所有简历及其标签
        List<ResumeTag> resumeTags = resumeTagMapper.getAllResumeTag();
        //进行分组
        Map<Integer,List<String>> map = new HashMap<>();
        for(ResumeTag resumeTag : resumeTags){
            if(map.containsKey(resumeTag.getResumeId())){
                List<String> x = map.get(resumeTag.getResumeId());
                x.add(resumeTag.getTagValue());
                map.put(resumeTag.getResumeId(),x);
            }else{
                map.put(resumeTag.getResumeId(),new ArrayList<>());
            }
        }
        List<ResumeMatch> matches = new ArrayList<>();

        //3.循环每个简历实体
        for(Map.Entry<Integer, List<String>> entry : map.entrySet()){
            //每个简历所包含的标签
            List<String> tags = entry.getValue();


            //3.1筛选硬性条件
            if(!this.meetsHardConditions(hard,tags)){
                continue;
            }

            //3.2计算匹配度
            double score = getScore(tags,conditions);
            if(score<=0){
                continue;
            }
            log.info("简历ID为: "+entry.getKey()+"满足硬性条件,且匹配度为: "+score);

            //3.3放入匹配集合中
            ResumeMatch resumeMatch = new ResumeMatch(entry.getKey(),score);
            matches.add(resumeMatch);
        }

        //4.针对匹配集合进行排序(从大到小)
        //matches.sort((o1, o2) -> (int) (o2.getScore()-o1.getScore()));
        //matches.sort(Comparator.comparingDouble(ResumeMatch::getScore).reversed());
        //5.根据策略返回简历个数
        return matches;
    }
    /**
     * 获取提示词
     * */
    @NotNull
    private  String getMessage(JobMatchVo jobDescription, List<Tag> labels) {
        StringBuilder labelSetNew=new StringBuilder();
        for (Tag label : labels) {
            labelSetNew.append(label.getTagValue()).append(",");
        }
        log.info("标签体系: "+labelSetNew);

        //2.构建提示词(注意：需要返回值按照一定的格式,故提示词需要限制),正确书写提示词确实对结果有所帮助
        if(jobDescription.getFocus() == null || jobDescription.getFocus().isEmpty()){
            //没有侧重点，则大模型自己研判并进行权重分配
            return String.format(MatchPrompt.MATCH_PROMPT1.getPrompt(),jobDescription.getJobDescription(),labelSetNew);
        }else {
            //有侧重点，则需要根据侧重点进行权重倾斜
            return String.format(MatchPrompt.MATCH_PROMPT2.getPrompt(),jobDescription.getJobDescription(),labelSetNew,jobDescription.getFocus());
        }

    }

    /**
     * 处理模型返回结果，提取想要的内容
     * */
    public  String[] processRet(String output){
        // 定义正则表达式
        String regex = "@([^@]*)@";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(output);

        // 查找并提取匹配的内容
        if (matcher.find()) {
            String matchedGroup = matcher.group(1); // 提取括号内的内容
            String[] values = matchedGroup.split(","); // 按逗号分隔
            log.info("提取后的值为: "+String.join(",", values));
            return values;
        } else {
            log.warn("没有找到标签");
        }
        return null;
    }

    /**
     * 硬性条件检查-方法(默认不合格)
     * 分为三类：等值比较[todo党员，应届]  and  等级[学历]  and  数值类比较[工作经验]
     * */
    private boolean meetsHardConditions(int[] hard,List<String> tags){
        //获取现有学历
        int have = -1;
        for(String tag : tags){
            if(education.containsKey(tag)){
                have=education.get(tag);
                break;
            }
        }

        //获取工作经验
        int now = 0;
        for(String tag : tags){
            if(tag.length()>=5 && tag.charAt(4)==':'){
                now = tag.charAt(5)-'0';
                break;
            }
        }
        if(hard[0]>have){
            return false;
        }
        return hard[1] <= now;
        /*//循环进行过滤
        for(String conditions : hardConditions){
            if(conditions.length()>=3 && conditions.charAt(2) == ':'){
                //学历处理
                int need = education.get(conditions.substring(3));//要求学历
                if(need > have){
                    return false;
                }
            }else if(conditions.length()>=5 && conditions.charAt(4) == ':'){
                //工作经验处理
                int time = conditions.charAt(5)-'0';
                if(time > now){
                    return false;
                }
            }else{
                //其他处理（党员、应届、驾照等）
                if(!tags.contains(conditions)){
                    return false;
                }
            }
        }
        return true;*/
    }


    //提取岗位所需学历+工作经验
    public int[] getEducationAndExperience(List<String> hardConditions){
        int need = -1;
        int time = 0;
        //循环进行过滤
        for(String conditions : hardConditions){
            if(conditions.length()>=3 && conditions.charAt(2) == ':'){
                //学历处理
                need = education.get(conditions.substring(3));//要求学历
            }else if(conditions.length()>=5 && conditions.charAt(4) == ':'){
                //工作经验处理
                if(Character.isDigit(conditions.charAt(5))){
                    time = conditions.charAt(5)-'0';
                }
            }
        }
        return new int[]{need,time};
    }

    /**
     * 类型转换,Job -> JobLabels
     * */
    private JobLabels convertToJobLabels(Job job){
        JobLabels jobLabels = new JobLabels(new ArrayList<>(),new ArrayList<>());
        String[] filters = job.getFilters().split(",");
        for(String filter : filters){
            jobLabels.getFilters().add(filter);
        }
        String[] conditions = job.getTags().split(",");
        for(String condition : conditions){
            String[] tmp = condition.split(":");
            jobLabels.getConditions().add(new TagWeight(tmp[0],Double.parseDouble(tmp[1])));
        }
        return jobLabels;
    }

    /**
     * 计算权重得分
     * @param tags 每个简历包含的标签
     * @param conditions JD提取的标签及权重
     * */
    private double getScore(List<String> tags, List<TagWeight> conditions){
        double score = 0;
        StringBuilder match = new StringBuilder();
        for(TagWeight condition : conditions){
            if(tags.contains(condition.getTag())){
                score+=condition.getWeight();
                match.append(condition.getTag()).append(",");
                //TODO:扩展点，可以加入其他的权重计算方式[TF-IDF]
            }
        }
        if(score>0){
            log.info("匹配到的标签为: "+match);
        }
        return score;
    }

}
